package cn.iocoder.boot.springai001.service;

import cn.hutool.core.util.StrUtil;
import cn.iocoder.boot.springai001.controller.dto.ChatRequest;
import cn.iocoder.boot.springai001.utils.MediaUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.content.Media;
import org.springframework.ai.model.tool.ToolCallingChatOptions;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;

import java.util.List;

/**
 * AI对话服务
 * <p>
 * 提供统一的对话处理逻辑，支持多种对话模式动态选择
 */
@Slf4j
@Service
public class ChatService {

    @Resource
    private ChatClient chatClient;

    @Resource
    private ChatClient.Builder chatClientBuilder;

    @Resource
    private ChatMemory chatMemory;

    @Resource
    private ISessionService sessionService;

    @Resource
    private StreamingToolCallingService streamingToolCallingService;

    @Resource
    private PromptTemplateManager promptTemplateManager;

    @Resource
    private CancellationService cancellationService;

    /**
     * 统一的对话入口，根据 chatMode 动态选择对话模式
     *
     * @param request 对话请求参数
     * @return 流式响应
     */
    public Flux<ChatResponse> chat(ChatRequest request) {
        // 检查 sessionId 是否传入
        String sessionId = request.getSessionId();
        if (StrUtil.isBlank(sessionId)) {
            log.error("sessionId 未传入");
            return Flux.error(new IllegalArgumentException("sessionId 不能为空，请先通过会话管理接口创建会话"));
        }

        log.info("【统一对话接口】模式: {}, 会话ID: {}, 用户ID: {}, 问题: {}",
                request.getChatMode(), request.getSessionId(), request.getUserId(), request.getQuery());

        // 如果会话已存在，更新活跃时间
        sessionService.getSession(sessionId).ifPresent(session ->
                sessionService.updateLastActive(sessionId)
        );

        // 根据对话模式调用不同的处理方法
        ChatRequest.ChatMode mode = request.getChatMode() != null
                ? request.getChatMode()
                : ChatRequest.ChatMode.BASIC;

        Flux<ChatResponse> baseFlux = switch (mode) {
            case BASIC -> basicChat(request, sessionId);
            case TASK_PLANNING -> taskPlanningChat(request, sessionId);
            case STREAMING_TOOLS_MANUAL -> streamingToolsManualChat(request, sessionId);
        };
        // 绑定取消信号：优先使用 requestId，其次回退到 sessionId
        String cancelKey = StringUtils.hasText(request.getRequestId()) ? request.getRequestId() : sessionId;
        return baseFlux
                .takeUntilOther(cancellationService.signalFlux(cancelKey))
                .doFinally(sig -> cancellationService.cleanup(cancelKey));
    }

    /**
     * 基础对话模式
     */
    private Flux<ChatResponse> basicChat(ChatRequest request, String sessionId) {
        return executeChat(
                chatClient,
                request.getQuery(),
                request.getPrompt(),
                request.getImageUrls(),
                request.getModel(),
                request.getTemperature(),
                sessionId,
                request.getEnableCoT(),
                request.getCotMode() != null ? request.getCotMode().name() : "ZERO_SHOT",
                request.getCotExample()
        );
    }

    /**
     * 任务规划对话模式
     * <p>
     * 支持任务规划 + CoT 组合使用：
     * - 任务规划：提供系统提示词（任务分解、工具选择、逻辑推理等）
     * - CoT：在处理用户问题时添加推理引导，提升推理能力
     * <p>
     * 组合策略：
     * 1. 系统提示词使用任务规划模板（工具执行、步骤分解）
     * 2. 用户问题经过 CoT 处理（添加推理引导）
     * 3. 两者协同：任务规划提供"做什么"，CoT 提供"怎么想"
     */
    private Flux<ChatResponse> taskPlanningChat(ChatRequest request, String sessionId) {
        // 任务规划系统提示词（定义角色、工具、执行规范）
        String taskPlanningPrompt = promptTemplateManager.buildTaskPlanningPrompt(
                request.getShowToolResults() != null ? request.getShowToolResults() : true);

        // 允许任务规划模式下也启用 CoT，增强推理能力
        Boolean enableCoT = request.getEnableCoT() != null ? request.getEnableCoT() : false;
        String cotMode = request.getCotMode() != null ? request.getCotMode().name() : "ZERO_SHOT";
        String cotExample = request.getCotExample();

        log.info("【任务规划模式】会话ID: {}, CoT: {}, CoT模式: {}", sessionId, enableCoT, cotMode);

        return executeChat(
                chatClient,
                request.getQuery(),
                taskPlanningPrompt,
                request.getImageUrls(),
                request.getModel(),
                request.getTemperature(),
                sessionId,
                enableCoT,  // 支持 CoT
                cotMode,     // CoT 模式
                cotExample   // CoT 示例
        );
    }

    /**
     * 流式工具调用对话模式（手动模式）
     */
    private Flux<ChatResponse> streamingToolsManualChat(ChatRequest request, String sessionId) {
        return streamingToolCallingService.streamingToolChat(
                request.getPrompt(),
                request.getQuery(),
                request.getImageUrls(),
                request.getModel(),
                request.getTemperature(),
                sessionId
        );
    }

    /**
     * 执行对话（使用默认的 ChatClient）
     *
     * @param query          用户问题
     * @param systemPrompt   系统提示词
     * @param imageUrls      图片URL列表
     * @param model          模型名称
     * @param temperature    温度参数
     * @param conversationId 会话ID
     * @return 流式响应
     */
    public Flux<ChatResponse> chat(String query,
                                   String systemPrompt,
                                   List<String> imageUrls,
                                   String model,
                                   Double temperature,
                                   String conversationId) {
        return executeChat(chatClient, query, systemPrompt, imageUrls, model, temperature, conversationId,
                false, null, null);
    }

    /**
     * 执行对话（使用默认的 ChatClient，支持思维链模式）
     *
     * @param query          用户问题
     * @param systemPrompt   系统提示词
     * @param imageUrls      图片URL列表
     * @param model          模型名称
     * @param temperature    温度参数
     * @param conversationId 会话ID
     * @param enableCoT      是否启用思维链模式
     * @param cotMode        思维链模式类型
     * @param cotExample     思维链示例（Few-shot模式使用）
     * @return 流式响应
     */
    public Flux<ChatResponse> chat(String query,
                                   String systemPrompt,
                                   List<String> imageUrls,
                                   String model,
                                   Double temperature,
                                   String conversationId,
                                   Boolean enableCoT,
                                   String cotMode,
                                   String cotExample) {
        return executeChat(chatClient, query, systemPrompt, imageUrls, model, temperature, conversationId,
                enableCoT, cotMode, cotExample);
    }

    /**
     * 执行对话（使用自定义工具集）
     *
     * @param toolCallbackProvider 工具提供者
     * @param query                用户问题
     * @param systemPrompt         系统提示词
     * @param imageUrls            图片URL列表
     * @param model                模型名称
     * @param temperature          温度参数
     * @param conversationId       会话ID
     * @return 流式响应
     */
    public Flux<ChatResponse> chatWithTools(ToolCallbackProvider toolCallbackProvider,
                                            String query,
                                            String systemPrompt,
                                            List<String> imageUrls,
                                            String model,
                                            Double temperature,
                                            String conversationId) {
        // 使用自定义工具创建 ChatClient（包含 ChatMemory 支持）
        ChatClient customClient = chatClientBuilder
                .defaultAdvisors(MessageChatMemoryAdvisor
                        .builder(chatMemory)
                        .build())
                .defaultToolCallbacks(toolCallbackProvider.getToolCallbacks())
                .build();

        return executeChat(customClient, query, systemPrompt, imageUrls, model, temperature, conversationId,
                false, null, null);
    }

    /**
     * 任务规划对话（专门用于复杂任务规划）
     * <p>
     * 针对需要多步骤、多工具协作的复杂任务，提供专门的任务规划能力
     * <p>
     * 使用场景示例：
     * - 查询昨天区县级效能指数，分析最低分区域，找出影响镇街
     * - 获取当前时间，查询特定日期的数据，进行多维度分析
     * - 需要按步骤执行、中间结果分析、最终总结的复杂任务
     *
     * @param query          用户问题
     * @param model          模型名称
     * @param temperature    温度参数
     * @param conversationId 会话ID
     * @return 流式响应
     */
    public Flux<ChatResponse> taskPlanningChat(String query,
                                               String model,
                                               Double temperature,
                                               String conversationId) {
        return taskPlanningChat(query, model, temperature, conversationId, true);
    }

    /**
     * 任务规划对话（支持详细模式控制）
     * <p>
     * 针对需要多步骤、多工具协作的复杂任务，提供专门的任务规划能力
     *
     * @param query           用户问题
     * @param model           模型名称
     * @param temperature     温度参数
     * @param conversationId  会话ID
     * @param showToolResults 是否显示工具执行结果
     * @return 流式响应
     */
    public Flux<ChatResponse> taskPlanningChat(String query,
                                               String model,
                                               Double temperature,
                                               String conversationId,
                                               Boolean showToolResults) {
        // 任务规划专用系统提示词
        String taskPlanningPrompt = promptTemplateManager.buildTaskPlanningPrompt(showToolResults);

        log.info("【任务规划对话】会话ID: {}, 模型: {}, 问题: {}, 显示工具结果: {}",
                conversationId, model, query, showToolResults);

        return executeChat(chatClient, query, taskPlanningPrompt, null, model, temperature, conversationId,
                false, null, null);
    }

    /**
     * 核心对话执行逻辑
     */
    private Flux<ChatResponse> executeChat(ChatClient client,
                                           String query,
                                           String systemPrompt,
                                           List<String> imageUrls,
                                           String model,
                                           Double temperature,
                                           String conversationId,
                                           Boolean enableCoT,
                                           String cotMode,
                                           String cotExample) {
        // 为 systemPrompt 提供安全默认值
        String safeSystemPrompt = StringUtils.hasText(systemPrompt)
                ? systemPrompt
                : "你是一个乐于助人的 AI 智能助手";

        // 记录请求日志
        String cotStatus = (enableCoT != null && enableCoT) ? cotMode : "未启用";
        log.info("执行对话 - 会话ID: {}, 模型: {}, 问题: {}, 图片数量: {}, CoT模式: {}, 系统提示词: {}",
                conversationId, model, query, imageUrls != null ? imageUrls.size() : 0,
                cotStatus, safeSystemPrompt.length() > 100 
                        ? safeSystemPrompt.substring(0, 100) + "..." : safeSystemPrompt);

        // 参数验证
        if (!StringUtils.hasText(query)) {
            log.warn("问题内容为空，会话ID: {}", conversationId);
            return Flux.error(new IllegalArgumentException("问题内容不能为空"));
        }

        // 温度参数修正
        double validTemperature = temperature;
        if (temperature < 0 || temperature > 1) {
            log.warn("温度参数超出范围: {}, 会话ID: {}", temperature, conversationId);
            validTemperature = Math.max(0, Math.min(1, temperature));
        }

        // 处理思维链（Chain of Thought）模式
        String processedQuery = promptTemplateManager.processChainOfThought(query, enableCoT, cotMode, cotExample);
        if (!query.equals(processedQuery)) {
            log.info("✓ 已启用思维链模式 - 模式: {}, 原始问题长度: {} 字符", cotMode, query.length());
            log.debug("思维链处理后问题:\n{}", processedQuery);
        } else if (enableCoT != null && enableCoT) {
            log.info("CoT 参数已设置但未生效（可能 enableCoT 为 false 或模式无效）");
        }

        try {
            // 构建聊天选项
            ChatOptions chatOptions = ToolCallingChatOptions.builder()
                    .model(model)
                    .internalToolExecutionEnabled(true)
                    .temperature(validTemperature)
                    .build();

            // 处理图片URL
            Media[] medias = MediaUtils.mediaArray(imageUrls);
            if (medias != null && medias.length > 0) {
                log.info("成功加载 {} 张图片用于多模态对话", medias.length);
            }

            // 构建并执行对话
            return client.prompt()
                    .system(safeSystemPrompt)
                    .user(u -> {
                        u.text(processedQuery);  // 使用处理后的问题（可能包含CoT提示）
                        if (medias != null && medias.length > 0) {
                            u.media(medias);
                        }
                    })
                    .options(chatOptions)
                    .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
                    .stream()
                    .chatResponse()
                    .doOnError(error -> log.error("对话处理出错，会话ID: {}, 错误: {}",
                            conversationId, error.getMessage(), error))
                    .doOnComplete(() -> log.info("对话完成，会话ID: {}", conversationId));

        } catch (Exception e) {
            log.error("对话请求处理失败，会话ID: {}, 错误: {}", conversationId, e.getMessage(), e);
            return Flux.error(new RuntimeException("抱歉，处理您的请求时出现错误：" + e.getMessage(), e));
        }
    }

}

